﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml;
using Models;

namespace Common
{
#pragma warning disable IDE1006 
  public static class PublicTool
  {
    private static readonly DateTime Maminitime = DateTime.Parse("1753-01-01 12:00:00");
    private static readonly string BaseDirectory = AppDomain.CurrentDomain.BaseDirectory + "\\Upload\\";
    public static string ApplicationHost
    {
      get
      {
        var meathos = MyHttpContext.Current.Request.IsHttps ? "https://" : "http://";
        var host = MyHttpContext.Current.Request.Host;
        var hostStr = host.Port == null || host.Port == 80 || host.Port == 443 ? host.Host : $"{host.Host}:{host.Port}";
        return $"{meathos}{hostStr}/";
      }
    }

    // 接口返回格式
    public class ComResult<T>
    {
      public int code { get; set; }
      public T data { get; set; }
    }

    // 生成Guid
    public static string NewGuid(bool format = false)
    {
      return format ? Guid.NewGuid().ToString().Replace("-", "") : Guid.NewGuid().ToString();
    }

    // 生成 min-max 间的随机数
    public static int Random(int min, int max)
    {
      return new Random(NewGuid().GetHashCode()).Next(min, max);
    }


    // 32位ID
    public static string GetOrder(long userindex, int length = 32)
    {
      var oreder = $"{userindex}{DateTime.Now:yyyyMMddHHmmssfff}{Random(1000, 10000)}{NewGuid().GetHashCode()}".Replace("-", "");
      return oreder.Substring(0, length);
    }

    // response 字典格式构造
    private static async Task<JsonResult> DicToJson<T>(T obj, int code)
    {
      var res = new ComResult<T>
      {
        code = code,
        data = obj
      };

      var setting = new JsonSerializerSettings
      {
        DateFormatHandling = DateFormatHandling.MicrosoftDateFormat,
        DateFormatString = "yyyy-MM-dd HH:mm:ss",
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
        //ContractResolver = new CamelCasePropertyNamesContractResolver(),
        Formatting = Newtonsoft.Json.Formatting.Indented
      };
      var json = new JsonResult(res, setting)
      {
        ContentType = "application/json; charset=utf-8",
        StatusCode = 200,
        Value = res
      };
      return await Task.Run(() => json);
    }

    // response xml格式构造
    public static SortedDictionary<string, object> XmlToDic(string xml)
    {
      if (string.IsNullOrWhiteSpace(xml)) return null;
      try
      {
        var paramdic = new SortedDictionary<string, object>();
        var xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(xml);
        var xmlNode = xmlDoc.FirstChild;
        var nodes = xmlNode.ChildNodes;
        var stringBuilder = new StringBuilder();
        foreach (XmlNode xn in nodes)
        {
          var xe = (XmlElement)xn;
          paramdic[xe.Name] = xe.InnerText;
          stringBuilder.Append($"{xe.Name}={xe.InnerText}&");
        }
        //Log4Help.Debug("Xml->" + stringBuilder);
        return paramdic;
      }
      catch (Exception)
      {
        return null;
      }
    }

    // response 字典格式转xml格式
    public static string DicToXml(SortedDictionary<string, object> param)
    {
      if (param == null || param.Count == 0) return null;

      var stringBuilder = new StringBuilder();

      stringBuilder.Append("<xml>");
      foreach (var itm in param)
      {
        if (string.IsNullOrWhiteSpace(itm.Value?.ToString()) || string.IsNullOrWhiteSpace(itm.Key)) continue;

        if (itm.Value is int)
        {
          stringBuilder.Append($"<{itm.Key}>{itm.Value}</{itm.Key}>");
        }

        if (itm.Value is string)
        {
          stringBuilder.Append($"<{itm.Key}><![CDATA[{itm.Value}]]></{itm.Key}>");
        }
      }
      stringBuilder.Append("</xml>");
      //Log4Help.Debug("Xml->" + stringBuilder);
      return stringBuilder.ToString();
    }

    // 请求Param参数转码
    public static string ParamToUrl(SortedDictionary<string, object> paramdic, bool paramserial = false)
    {
      return paramserial ? paramdic.Aggregate("", (current, itm) => current + $"{System.Web.HttpUtility.UrlEncode(itm.Key)}={System.Web.HttpUtility.UrlEncode(itm.Value.ToString())}&").TrimEnd('&') : paramdic.Aggregate("", (current, itm) => current + $"{itm.Key}={itm.Value.ToString()}&").TrimEnd('&');
    }

    // 带编码的url转Param参数
    public static bool UrlToParam(string url, out Dictionary<string, string> paramdic)
    {
      paramdic = new Dictionary<string, string>();
      if (string.IsNullOrWhiteSpace(url)) return false;
      url = url.Contains("?") ? url.Split('?')[1] : url;

      try
      {
        paramdic = url.Split('&').Select(itm => itm.Split('=')).Where(itmsplit => itmsplit.Length == 2).ToDictionary(itmsplit => System.Web.HttpUtility.UrlDecode(itmsplit[0] ?? ""), itmsplit => System.Web.HttpUtility.UrlDecode(itmsplit[1] ?? ""));
        return true;
      }
      catch (Exception)
      {
        return false;
      }
    }

    // 返回成功返回格式
    public static async Task<JsonResult> ReturnSuccess<T>(T obj, int code = 0 )
    {
      return await DicToJson(obj, code);
    }

    // 返回失败返回格式
    public static async Task<JsonResult> ReturnError<T>(T obj, int code = -1)
    {
      return await DicToJson(obj, code);
    }

    public static async Task<ContentResult> ReturnSuccessJsonp(object obj, int code = 0)
    {
      return await ReturnJsonp(obj, code);
    }

    public static async Task<ContentResult> ReturnErrorJsonp(object obj, int code = -1)
    {
      return await ReturnJsonp(obj, code);
    }
    private static async Task<ContentResult> ReturnJsonp<T>(T obj, int code = 0)
    {
      var json = JsonResultToStr(await DicToJson(obj, code));

      JsonpAction(out var callback);

      return await Task.Run(() => new ContentResult
      {
        Content = $"{callback}({json})",
        ContentType = "text/plain",
        StatusCode = 200
      });
    }


    public static bool JsonpAction(out string callback)
    {
      callback = "";
      MyHttpContext.Current.Request.Query.TryGetValue("callback", out var callbacks);
      callback = callbacks.FirstOrDefault() ?? "callback";
      return !string.IsNullOrWhiteSpace(callbacks.FirstOrDefault());
    }
    public static async Task<ContentResult> ReturnXml(bool state)
    {
      var returnCode = state ? "SUCCESS" : "FAIL";

      var sortedDictionary = new SortedDictionary<string, object>
            {
                { "return_code",returnCode}
            };

      return await Task.Run(() => new ContentResult
      {
        Content = DicToXml(sortedDictionary),
        ContentType = "text/plain",
        StatusCode = 200
      });
    }
    public static string JsonResultToStr(JsonResult json)
    {
      return JObject.FromObject(json.Value).ToString();
    }



    public static async Task<string> ReturnString(string data)
    {
      return await Task.Run(() => data);
    }
    private static bool ValidateChineseString(string value)
    {
      if (string.IsNullOrWhiteSpace(value)) return false;

      const string regstr = "^[\\u4e00-\\u9fa5]{0,}$";

      return Regex.IsMatch(value, regstr);
    }



    public static bool TimeIsMonth(string value)
    {
      if (string.IsNullOrWhiteSpace(value))
      {
        return false;
      }

      var batch = FormatStr(value.Replace("-", "").Replace("\\", "").Replace("年", "").Replace("月", "").Replace("日", ""));

      return batch.Length == 6;
    }

    public static DateTime DataTimeParse(string value, int length = 8)
    {
      if (string.IsNullOrWhiteSpace(value))
      {
        return Maminitime;
      }
      value = FormatStr(value);

      if (value.Equals("0000-00-00 00:00:00") || value.Length < length)
      {
        return Maminitime;
      }

      try
      {
        var time = DateTime.Parse(value);
        return time < Maminitime ? Maminitime : time;
      }
      catch (Exception)
      {
        // ignored
      }

      var year = value.Substring(0, 4);
      var month = value.Substring(4, 2);
      var day = value.Substring(6, 2);
      var hour = "00";
      var minute = "00";
      var second = "00";

      if (int.Parse(month) > 12 || int.Parse(day) > 31)
      {
        return Maminitime;
      }

      if (!value.Contains(" "))
      {
        return DateTime.Parse(year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second);
      }
      var timevalve = value.Split(' ')[1];

      if (timevalve.Length >= 2)
      {
        hour = timevalve.Substring(0, 2);
      }

      if (timevalve.Length >= 4)
      {
        minute = timevalve.Substring(3, 2);
      }

      if (timevalve.Length >= 6)
      {
        second = timevalve.Substring(5, 2);
      }

      hour = int.Parse(hour) > 23 ? "00" : hour;
      minute = int.Parse(minute) > 59 ? "00" : minute;
      second = int.Parse(second) > 59 ? "00" : second;

      return DateTime.Parse(year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second);
    }
    public static string FormatStr(string value)
    {
      if (value == null) return "";

      var revalue =
          value.TrimStart('"')
              .TrimEnd('"')
              .TrimStart(',')
              .TrimEnd(',')
              .TrimStart('\'')
              .TrimEnd('\'')
              .TrimStart(' ')
              .TrimEnd(' ')
              .TrimStart('\r')
              .TrimEnd('\r')
              .TrimStart('\n')
              .TrimEnd('\n');

      return revalue;
    }

    public static bool IsInt(string value)
    {
      return Regex.IsMatch(value, @"^\d*$");
    }
    public static string GetTimeStamp()
    {
      var ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
      return (Convert.ToInt64(ts.TotalSeconds) + 10000).ToString();
    }
    public static DateTime ConvertTimestamp(long timestamp)
    {
      var converted = new DateTime(1970, 1, 1, 0, 0, 0, 0);
      var newDateTime = converted.AddMilliseconds(timestamp);
      return newDateTime.ToLocalTime();
    }


    public static string ByteToBase64String(byte[] data)
    {
      try
      {
        return $"data:image/png;base64,{Convert.ToBase64String(data)}";
      }
      catch (Exception)
      {
        return null;
      }
    }

    public static string TimRandom(int length, bool hasnum = true, bool hasEnglish = false)
    {
      var random = "";
      var randomlist = new List<string>();
      if (hasnum)
      {
        for (var i = 0; i <= 9; i++)
        {
          randomlist.Add(i.ToString());
        }
      }

      if (hasEnglish)
      {
        for (var i = 'A'; i <= 'F'; i++)
        {
          randomlist.Add(i.ToString());
        }
      }

      for (var i = 0; i < length; i++)
      {
        random += randomlist[new Random(NewGuid().GetHashCode()).Next(randomlist.Count)];
      }
      return random;
    }
    public static byte[] DecodeBase64ToByte(string result)
    {
      try
      {
        return Convert.FromBase64String(result);
      }
      catch
      {
        return null;
      }
    }
    public static string EcodeBase64(byte[] result)
    {
      try
      {
        return Convert.ToBase64String(result);
      }
      catch (Exception)
      {
        return null;
      }
    }
    public static string GetString(byte[] soure)
    {
      try
      {
        return Encoding.UTF8.GetString(soure);
      }
      catch (Exception)
      {
        return null;
      }
    }
    public static byte[] GetBytes(string soure)
    {
      try
      {
        return Encoding.UTF8.GetBytes(soure);
      }
      catch (Exception)
      {
        return null;
      }
    }
    public static string DecodeBase64(Encoding encode, string result)
    {
      try
      {
        var bytes = DecodeBase64ToByte(result);
        return encode.GetString(bytes);
      }
      catch (Exception)
      {
        return null;
      }
    }
    public static List<T> DeserializeObject<T>(string source)
    {
      try
      {
        return JsonConvert.DeserializeObject<List<T>>(source) ?? new List<T>();
      }
      catch (Exception)
      {
        return new List<T>();
      }
    }
    public static string SerializeObject(object obj)
    {
      try
      {
        return JsonConvert.SerializeObject(obj);
      }
      catch (Exception)
      {
        return null;
      }
    }
    public static string Decrypt(string decryptStr, string key)
    {
      try
      {
        var keyArray = Encoding.UTF8.GetBytes(key);
        var toEncryptArray = Convert.FromBase64String(decryptStr);
        var rDel = new RijndaelManaged
        {
          Key = keyArray,
          Mode = CipherMode.ECB,
          Padding = PaddingMode.PKCS7
        };
        var cTransform = rDel.CreateDecryptor();
        var resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
        return Encoding.UTF8.GetString(resultArray);
      }
      catch (Exception)
      {
        return null;
      }
    }

    public static string Md5Encryption(string myString)
    {
      using (var md5 = MD5.Create())
      {
        var result = md5.ComputeHash(Encoding.UTF8.GetBytes(myString));
        var strResult = BitConverter.ToString(result);
        return strResult.Replace("-", "");
      }
    }

    public static byte[] StreamToBytes(Stream stream)
    {
      var outstream = new MemoryStream();
      const int bufferLen = 1;
      var buffer = new byte[bufferLen];
      var count = 0;
      while ((count = stream.Read(buffer, 0, bufferLen)) > 0)
      {
        outstream.Write(buffer, 0, count);
      }

      outstream.Seek(0, SeekOrigin.Begin);
      var bytes = new byte[outstream.Length];
      outstream.Read(bytes, 0, bytes.Length);
      outstream.Flush();
      outstream.Close();
      if (stream.CanSeek)
      {
        stream.Seek(0, SeekOrigin.Begin);
      }
      else
      {
        stream.Close();
      }
      return bytes;
    }


    public static Stream BytesToStream(byte[] bytes)
    {
      Stream stream = new MemoryStream(bytes);
      return stream;
    }
    public static byte[] FileToByte(string filename, string filepath = null)
    {
      filepath = string.IsNullOrWhiteSpace(filepath) ? BaseDirectory : filepath;
      if (!Directory.Exists(filepath)) Directory.CreateDirectory(filepath);
      try
      {
        using (var read = new FileInfo(Path.Combine(filepath, filename)).OpenRead())
        {
          var buffer = new byte[read.Length];
          read.Read(buffer, 0, Convert.ToInt32(read.Length));
          read.Close();
          return buffer;
        }
      }
      catch (Exception)
      {
        return null;
      }
    }

    public static string ReadFile(string filename, string filepath = null)
    {
      return Encoding.UTF8.GetString(FileToByte(filename, filepath) ?? new byte[0]);
    }

    public static string WriteFile(string filename, byte[] bytes, string filepath = null)
    {
      filepath = string.IsNullOrWhiteSpace(filepath) ? BaseDirectory : filepath;
      if (!Directory.Exists(filepath)) Directory.CreateDirectory(filepath);
      var realfile = Path.Combine(filepath, filename);
      try
      {
        using (var file = new FileStream(realfile, FileMode.OpenOrCreate, FileAccess.Write))
        {
          file.Write(bytes, 0, bytes.Length);
          file.Close();
        }
      }
      catch (Exception)
      {
        realfile = null;
      }
      return realfile;
    }
    public static string WriteFile(string filename, Stream stream, string filepath = null)
    {
      return WriteFile(filename, StreamToBytes(stream), filepath);
    }
    public static string WriteFile(string filename, string str, string filepath = null)
    {
      return WriteFile(filename, Encoding.UTF8.GetBytes(str), filepath);
    }

    public static bool LastVersion(int platform, string version, out string lastVersion)
    {
      lastVersion = "";

      var versionPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Version");
      if (!Directory.Exists(versionPath)) Directory.CreateDirectory(versionPath);

      try
      {
        var nowVersion = new Version(version);
        var maxVersion = new Version(version);

        foreach (var item in new DirectoryInfo(versionPath).GetFiles())
        {
          var itemVersion = new Version(Path.GetFileNameWithoutExtension(item.FullName));

          if (platform == 1)
          {
            if (item.Extension != ".apk") continue;
            if (itemVersion <= maxVersion) continue;
            maxVersion = itemVersion;
          }

          if (platform == 2)
          {
            if (item.Extension != ".ipa") continue;
            if (itemVersion <= maxVersion) continue;
            maxVersion = itemVersion;
          }
        }

        lastVersion = maxVersion.ToString();
        return maxVersion <= nowVersion;
      }
      catch (Exception)
      {
        return true;
      }
    }

    public static bool GetVersion(int platform, string version, out byte[] lastVersion)
    {
      lastVersion = new byte[] { };

      var versionPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Version");
      if (!Directory.Exists(versionPath)) Directory.CreateDirectory(versionPath);

      if (platform == 1)
      {
        lastVersion = FileToByte($"{version}.apk", versionPath);
      }

      if (platform == 2)
      {
        lastVersion = FileToByte($"{version}.apk", versionPath);
      }

      return lastVersion != null;
    }

    public static void Debug(string message)
    {
      //var ip = UserInfo.Ip;

      //Log4Help.Debug($"IP:{ip},{message}");
    }
    public static string left(string text, int li)
    {
      return text.Substring(0, li);
    }
    public static string right(string text, int li)
    {
      return text.Substring(text.Length - li, li);
    }
#pragma warning restore IDE1006

  }
}
